package com.xyht.sca_s.student_manage_system.modules.meeting.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.*;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.req.SmsPredetermineApplyAllowReq;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.req.SmsPredetermineApplyReq;
import com.xyht.sca_s.student_manage_system.modules.meeting.entity.resp.*;
import com.xyht.sca_s.student_manage_system.modules.meeting.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.meeting.service.SmsMeetingRoomPredetermineApplyService;
import com.xyht.sca_s.student_manage_system.modules.meeting.util.AddMeetingUtil;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.AppTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.RangeTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.TipsTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.org.entity.SmsOrgStructure;
import com.xyht.sca_s.student_manage_system.modules.org.mapper.SmsOrgStructureMapper;
import com.xyht.sca_s.student_manage_system.modules.scheduleManagement.util.ScheduleManagementUtil;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.entity.resp.SmsSearchUserResp;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomAllowStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomAllowTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomBooleanConstant.MEETING_ROOM_BOOLEAN_TRUE;
import static com.xyht.sca_s.student_manage_system.modules.meeting.constant.MeetingRoomDetailAllowStatusConstant.*;

/**
 * <p>
 * 会议室预定申请表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-08-03
 */
@Service
public class SmsMeetingRoomPredetermineApplyServiceImpl extends ServiceImpl<SmsMeetingRoomPredetermineApplyMapper, SmsMeetingRoomPredetermineApply> implements SmsMeetingRoomPredetermineApplyService {
    @Resource
    private SmsMeetingRoomPredetermineApplyMapper smsMeetingRoomPredetermineApplyMapper;
    @Resource
    private SmsMeetingRoomInfoMapper smsMeetingRoomInfoMapper;
    @Resource
    private SmsMeetingRoomProcessDetailMapper smsMeetingRoomProcessDetailMapper;
    @Resource
    private NewTipsUtil newTipsUtil;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private SmsMeetingRoomProcessDetailMPJMapper smsMeetingRoomProcessDetailMPJMapper;
    @Resource
    private SmsOrgStructureMapper smsOrgStructureMapper;
    @Resource
    private SmsMeetingBuildingMapper smsMeetingBuildingMapper;
    @Resource
    private SmsMeetingBuildingFloorMapper smsMeetingBuildingFloorMapper;
    @Resource
    private ScheduleManagementUtil scheduleManagementUtil;
    @Resource
    private AddMeetingUtil addMeetingUtil;

    @Override
    @Transactional
    public ResponseResult submitPredetermineApply(SmsPredetermineApplyReq applyReq, String userId) {
        //校验前端传入参数
        if (isNullOrEmpty(applyReq.getName()) || isNullOrEmpty(applyReq.getMeetingRoomId())
                || isNullOrEmpty(applyReq.getStartTime()) || isNullOrEmpty(applyReq.getEndTime())
                || isNullOrEmpty(applyReq.getMemberIdList())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        //校验会议室预约时间
        Date startDate = TimeUtil.StringtoDate(applyReq.getStartTime());
        Date endDate = TimeUtil.StringtoDate(applyReq.getEndTime());
        if (startDate.compareTo(endDate) > 0 || endDate.compareTo(TimeUtil.GetEndDate(startDate)) > 0 || startDate.compareTo(new Date()) < 0) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_TIME_ILLEGAL);
        }

        //校验会议室是否存在
        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(applyReq.getMeetingRoomId());
        if (isNullOrEmpty(meetingRoom)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_EXIST);
        }
        //校验会议室状态
        if (!meetingRoom.getIsUse()) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_IS_USE);
        }
        //校验容量
        if (applyReq.getMemberIdList().size() > meetingRoom.getCapacity()) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_CAPACITY_NOT_ENOUGH);
        }
        //校验会议室预定时间
        if (meetingRoom.getIsBookTime()) {
            //校验开始时间和结束时间限制
            Date startTimeLimit = TimeUtil.StringtoDate(applyReq.getStartTime());
            startTimeLimit.setHours(meetingRoom.getStartTimeLimit().getHours());
            startTimeLimit.setMinutes(meetingRoom.getStartTimeLimit().getMinutes());
            startTimeLimit.setSeconds(meetingRoom.getStartTimeLimit().getSeconds());
            Date endTimeLimit = TimeUtil.StringtoDate(applyReq.getEndTime());
            endTimeLimit.setHours(meetingRoom.getEndTimeLimit().getHours());
            endTimeLimit.setMinutes(meetingRoom.getEndTimeLimit().getMinutes());
            endTimeLimit.setSeconds(meetingRoom.getEndTimeLimit().getSeconds());

            if (!((startDate.compareTo(startTimeLimit) > 0 && startDate.compareTo(endTimeLimit) < 0)
                    && (endDate.compareTo(startTimeLimit) > 0 && endDate.compareTo(endTimeLimit) < 0))) {
                return CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_BOOKING_TIME_RANGE);
            }
            //校验是否超出会议室单次可预订时长上限
            long applyStartDateTime = startDate.getTime();
            long applyEndDateTime = endDate.getTime();
            int minutes = (int) ((applyEndDateTime - applyStartDateTime) / (1000 * 60));
            if (minutes > meetingRoom.getSingleTimeLimit()) {
                return CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_MAX_SINGLE_BOOKING_TIME);
            }
            //校验是否超出会议室最早可提前预定时间
            long nowTime = new Date().getTime();
            int hours = (int) ((applyStartDateTime - nowTime) / (1000 * 60 * 60));
            if (hours > meetingRoom.getEarliestBookTime()) {
                return CommonResult.failed(CommonCodeEnum.EXCEEDING_THE_EARLIEST_BOOKING_TIME);
            }
        }

        //校验是否有申请 存在交集
        Integer count = smsMeetingRoomPredetermineApplyMapper.selectCount(new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                .eq(SmsMeetingRoomPredetermineApply::getMeetingRoomId, applyReq.getMeetingRoomId())
                .eq(SmsMeetingRoomPredetermineApply::getAllowStatus, MEETING_ALLOW_STATUS_PASS)
                .not(queryWrapper ->
                        queryWrapper.le(SmsMeetingRoomPredetermineApply::getEndTime, startDate)
                                .or()
                                .ge(SmsMeetingRoomPredetermineApply::getStartTime, endDate)));
        if (count > 0) {
            return CommonResult.failed(CommonCodeEnum.CURRENT_TIME_CONFLICTS_WITH_OTHER_MEETING);
        }

        //创建预定申请表
        SmsMeetingRoomPredetermineApply predetermineApply = new SmsMeetingRoomPredetermineApply();
        BeanUtils.copyProperties(applyReq, predetermineApply);
        predetermineApply.setUserId(userId);
        predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_WAIT);
        predetermineApply.setStartTime(startDate);
        predetermineApply.setEndTime(endDate);
        predetermineApply.setMemberIdList(JSON.toJSONString(applyReq.getMemberIdList()));
        smsMeetingRoomPredetermineApplyMapper.insert(predetermineApply);

        //校验是否需要审批 同时 进行通知
        if (meetingRoom.getIsAllow()) {
            List<String> AllowUserIdList = JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class);
            for (String allowUserId : AllowUserIdList) {
                SmsMeetingRoomProcessDetail addDetail = new SmsMeetingRoomProcessDetail();
                addDetail.setApplyId(predetermineApply.getId());
                addDetail.setIsSign(meetingRoom.getIsSign() ? 1 : 0);
                addDetail.setIsStamp(meetingRoom.getIsStamp() ? 1 : 0);
                addDetail.setUserId(allowUserId);
                addDetail.setAllowStatus(MEETING_DETAIL_ALLOW_STATUS_WAIT);
                smsMeetingRoomProcessDetailMapper.insert(addDetail);

                //消息通知
                List<String> rangeList = new ArrayList<>();
                rangeList.add(allowUserId);
                newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                        userId,
                        RangeTypeEnum.RANGE_TYPE_ENUM_PERSON,
                        rangeList,
                        AppTypeEnum.APP_TYPE_ENUM_MEETING_ROOM,
                        predetermineApply.getId(),
                        addDetail.getId());
            }
        } else {
            predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_PASS);
            predetermineApply.setApplyEndTime(new Date());
            smsMeetingRoomPredetermineApplyMapper.updateById(predetermineApply);

            //消息通知
            newTipsUtil.allowFinishTips(predetermineApply.getId(), userId, true);
        }

        //添加日程
        scheduleManagementUtil.addSingleSchedule(predetermineApply.getId(),
                applyReq.getName(),
                applyReq.getMemberIdList(),
                startDate,
                endDate,
                userId,
                1,
                addMeetingUtil.getMeetingAddress(meetingRoom),
                applyReq.getRemark() == null ? "" : applyReq.getRemark(),
                1);

        return CommonResult.success();
    }

    @Override
    public ResponseResult cancelPredetermineApply(SmsPredetermineApplyReq cancelReq, String userId) {
        //校验前端参数
        if (isNullOrEmpty(cancelReq.getId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //校验会议室预定表是否存在
        SmsMeetingRoomPredetermineApply predetermineApply = smsMeetingRoomPredetermineApplyMapper.selectById(cancelReq.getId());
        if (isNullOrEmpty(predetermineApply)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_APPLY_NOT_EXIST);
        }
        //若非待审批状态不可撤回
        if (predetermineApply.getAllowStatus() != MEETING_DETAIL_ALLOW_STATUS_WAIT) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_ALLOWED_CANCEL_FAIL);
        }

        //撤回审批
        predetermineApply.setAllowStatus(MEETING_ALLOW_STATUS_CANCEL);
        predetermineApply.setApplyEndTime(new Date());
        smsMeetingRoomPredetermineApplyMapper.updateById(predetermineApply);

        //修改节点状态
        List<SmsMeetingRoomProcessDetail> detailList = smsMeetingRoomProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsMeetingRoomProcessDetail>()
                .eq(SmsMeetingRoomProcessDetail::getApplyId, predetermineApply.getId()));
        if (!detailList.isEmpty()) {
            for (SmsMeetingRoomProcessDetail detail : detailList) {
                SmsMeetingRoomProcessDetail updateDetail = new SmsMeetingRoomProcessDetail();
                updateDetail.setId(detail.getId());
                updateDetail.setAllowStatus(MEETING_DETAIL_ALLOW_STATUS_CANCELED);
                smsMeetingRoomProcessDetailMapper.updateById(updateDetail);
            }
        }

        //消息通知
        newTipsUtil.cancelFinishTips(cancelReq.getId());

        //删除日程
        scheduleManagementUtil.deleteSingleSchedule(predetermineApply.getId());

        return CommonResult.success();
    }

    @Override
    public ResponseResult getPredetermineApplyList(String userId, Integer applyType, Integer pageNum, Integer pageSize) {
        //校验前端参数
        if (isNullOrEmpty(applyType)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //构造回传数据
        List<MeetingRoomPredetermineApplyResp> respList = new ArrayList<>();
        int total = 0;

        //根据applyType进行相关处理
        if (applyType == MEETING_ROOM_ALLOW_TYPE_APPLY) {//已发起
            Page<SmsMeetingRoomPredetermineApply> page = new Page<>(pageNum, pageSize);
            smsMeetingRoomPredetermineApplyMapper.selectPage(page, new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                    .eq(SmsMeetingRoomPredetermineApply::getUserId, userId)
                    .orderByDesc(SmsMeetingRoomPredetermineApply::getStartTime));
            respList = page.getRecords().stream().map(apply -> {
                MeetingRoomPredetermineApplyResp applyResp = new MeetingRoomPredetermineApplyResp();
                BeanUtils.copyProperties(apply, applyResp);
                SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(apply.getMeetingRoomId());
                if (!isNullOrEmpty(meetingRoom)) {
                    SmsMeetingRoomInfoResp meetingRoomInfoResp = new SmsMeetingRoomInfoResp();
                    BeanUtils.copyProperties(meetingRoom, meetingRoomInfoResp);
                    SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
                    meetingRoomInfoResp.setBuildingName(building.getName());
                    SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
                    meetingRoomInfoResp.setFloorName(floor.getName());
                    applyResp.setMeetingRoomInfo(meetingRoomInfoResp);
                }
                applyResp.setMemberIdList(JSON.parseArray(apply.getMemberIdList(), String.class));
                //获取当前用户信息并进行设置
                SmsUser smsUser = cacheUtil.getUserInfo(apply.getUserId());
                SmsSearchUserResp userResp = new SmsSearchUserResp();
                if (smsUser != null) {
                    BeanUtils.copyProperties(smsUser, userResp);
                }
                applyResp.setApplyUserInfo(userResp);
                return applyResp;
            }).collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (applyType == MEETING_ROOM_ALLOW_TYPE_ALLOWED) {//已办
            Page<SmsMeetingRoomPredetermineApplyMPJResp> page = new Page<>(pageNum, pageSize);
            MPJLambdaWrapper<SmsMeetingRoomProcessDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
            mpjLambdaWrapper.selectAll(SmsMeetingRoomProcessDetail.class).selectAll(SmsMeetingRoomPredetermineApply.class)
                    .selectAs(SmsMeetingRoomPredetermineApply::getCreateTime, "applyCreateTime")
                    .selectAs(SmsMeetingRoomProcessDetail::getId, "detailId")
                    .selectAs(SmsMeetingRoomPredetermineApply::getEndTime, "endTime")
                    .selectAs(SmsMeetingRoomPredetermineApply::getUserId, "applyUserId")
                    .selectAs(SmsMeetingRoomProcessDetail::getUserId, "allowUserId")
                    .selectAs(SmsMeetingRoomPredetermineApply::getRemark, "applyRemark")
                    .selectAs(SmsMeetingRoomProcessDetail::getRemark, "processDetailRemark")
                    .selectAs(SmsMeetingRoomProcessDetail::getAllowStatus, "processDetailStatus")
                    .leftJoin(SmsMeetingRoomPredetermineApply.class, SmsMeetingRoomPredetermineApply::getId, SmsMeetingRoomProcessDetail::getApplyId)
                    .eq(SmsMeetingRoomProcessDetail::getUserId, userId)
                    .orderByDesc(SmsMeetingRoomPredetermineApply::getCreateTime)
                    .orderByDesc(SmsMeetingRoomProcessDetail::getEndTime);
            smsMeetingRoomProcessDetailMPJMapper.selectJoinPage(page, SmsMeetingRoomPredetermineApplyMPJResp.class, mpjLambdaWrapper);

            respList = page.getRecords().stream()
                    .map(smsMPJResp -> {
                        MeetingRoomPredetermineApplyResp applyResp = new MeetingRoomPredetermineApplyResp();
                        BeanUtils.copyProperties(smsMPJResp, applyResp);
                        applyResp.setMemberIdList(JSON.parseArray(smsMPJResp.getMemberIdList(), String.class));
                        applyResp.setCreateTime(smsMPJResp.getApplyCreateTime());
                        applyResp.setEndTime(smsMPJResp.getApplyEndTime());
                        applyResp.setId(smsMPJResp.getApplyId());
                        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(smsMPJResp.getMeetingRoomId());
                        if (!isNullOrEmpty(meetingRoom)) {
                            SmsMeetingRoomInfoResp meetingRoomInfoResp = new SmsMeetingRoomInfoResp();
                            BeanUtils.copyProperties(meetingRoom, meetingRoomInfoResp);
                            SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
                            meetingRoomInfoResp.setBuildingName(building.getName());
                            SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
                            meetingRoomInfoResp.setFloorName(floor.getName());
                            applyResp.setMeetingRoomInfo(meetingRoomInfoResp);
                        }

                        SmsUser applyUser = cacheUtil.getUserInfo(applyResp.getApplyUserId());
                        SmsSearchUserResp applyUserResp = new SmsSearchUserResp();
                        if (applyUser != null) {
                            BeanUtils.copyProperties(applyUser, applyUserResp);
                        }
                        applyResp.setApplyUserInfo(applyUserResp);

                        SmsUser allowUser = cacheUtil.getUserInfo(applyResp.getAllowUserId());
                        SmsSearchUserResp allowUserResp = new SmsSearchUserResp();
                        if (allowUser != null) {
                            BeanUtils.copyProperties(allowUser, allowUserResp);
                        }
                        applyResp.setAllowUserInfo(allowUserResp);
                        return applyResp;
                    }).collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (applyType == MEETING_ROOM_ALLOW_TYPE_WAIT_ALLOW) {//待办
            //获取到当前用户待审批节点集合
            List<SmsMeetingRoomProcessDetail> detailList = smsMeetingRoomProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsMeetingRoomProcessDetail>()
                    .eq(SmsMeetingRoomProcessDetail::getUserId, userId)
                    .eq(SmsMeetingRoomProcessDetail::getAllowStatus, MEETING_DETAIL_ALLOW_STATUS_WAIT));
            List<String> detailIDList = detailList.stream().map(SmsMeetingRoomProcessDetail::getId).collect(Collectors.toList());
            Page<SmsMeetingRoomPredetermineApplyMPJResp> page = new Page<>(pageNum, pageSize);
            MPJLambdaWrapper<SmsMeetingRoomProcessDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
            mpjLambdaWrapper.selectAll(SmsMeetingRoomProcessDetail.class).selectAll(SmsMeetingRoomPredetermineApply.class)
                    .selectAs(SmsMeetingRoomPredetermineApply::getCreateTime, "applyCreateTime")
                    .selectAs(SmsMeetingRoomProcessDetail::getId, "detailId")
                    .selectAs(SmsMeetingRoomPredetermineApply::getEndTime, "endTime")
                    .selectAs(SmsMeetingRoomPredetermineApply::getUserId, "applyUserId")
                    .selectAs(SmsMeetingRoomProcessDetail::getUserId, "allowUserId")
                    .selectAs(SmsMeetingRoomPredetermineApply::getRemark, "applyRemark")
                    .selectAs(SmsMeetingRoomProcessDetail::getAllowStatus, "processDetailStatus")
                    .leftJoin(SmsMeetingRoomPredetermineApply.class, SmsMeetingRoomPredetermineApply::getId, SmsMeetingRoomProcessDetail::getApplyId)
                    .orderByDesc(SmsMeetingRoomPredetermineApply::getCreateTime)
                    .orderByDesc(SmsMeetingRoomProcessDetail::getCreateTime);
            if (detailIDList.isEmpty()) {
                detailIDList.add("");
            }
            mpjLambdaWrapper.in(SmsMeetingRoomProcessDetail::getId, detailIDList);
            smsMeetingRoomProcessDetailMPJMapper.selectJoinPage(page, SmsMeetingRoomPredetermineApplyMPJResp.class, mpjLambdaWrapper);

            respList = page.getRecords().stream()
                    .map(smsApplyMPJResp -> {
                        MeetingRoomPredetermineApplyResp applyResp = new MeetingRoomPredetermineApplyResp();
                        BeanUtils.copyProperties(smsApplyMPJResp, applyResp);
                        applyResp.setMemberIdList(JSON.parseArray(smsApplyMPJResp.getMemberIdList(), String.class));
                        applyResp.setCreateTime(smsApplyMPJResp.getApplyCreateTime());
                        applyResp.setId(smsApplyMPJResp.getApplyId());
                        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(smsApplyMPJResp.getMeetingRoomId());
                        if (!isNullOrEmpty(meetingRoom)) {
                            SmsMeetingRoomInfoResp meetingRoomInfoResp = new SmsMeetingRoomInfoResp();
                            BeanUtils.copyProperties(meetingRoom, meetingRoomInfoResp);
                            SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
                            meetingRoomInfoResp.setBuildingName(building.getName());
                            SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
                            meetingRoomInfoResp.setFloorName(floor.getName());
                            applyResp.setMeetingRoomInfo(meetingRoomInfoResp);
                        }

                        SmsUser applyUser = cacheUtil.getUserInfo(smsApplyMPJResp.getApplyUserId());
                        SmsSearchUserResp smsExamineUserResp = new SmsSearchUserResp();
                        if (applyUser != null) {
                            BeanUtils.copyProperties(applyUser, smsExamineUserResp);
                        }
                        applyResp.setApplyUserInfo(smsExamineUserResp);
                        return applyResp;
                    }).collect(Collectors.toList());
            total = (int) page.getTotal();
        }

        return CommonResult.success(respList, total);
    }

    @Override
    public ResponseResult getPredetermineApplyDetail(String applyId, String userId) {
        if (isNullOrEmpty(applyId)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsMeetingRoomPredetermineApply predetermineApply = smsMeetingRoomPredetermineApplyMapper.selectById(applyId);
        if (isNullOrEmpty(predetermineApply)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_APPLY_NOT_EXIST);
        }

        MeetingRoomPredetermineApplyResp applyResp = new MeetingRoomPredetermineApplyResp();
        BeanUtils.copyProperties(predetermineApply, applyResp);
        applyResp.setApplyUserId(predetermineApply.getUserId());
        applyResp.setMemberIdList(JSON.parseArray(predetermineApply.getMemberIdList(), String.class));
        applyResp.setApplyRemark(predetermineApply.getRemark());
        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(applyResp.getMeetingRoomId());
        if (!isNullOrEmpty(meetingRoom)) {
            SmsMeetingRoomInfoResp meetingRoomInfoResp = new SmsMeetingRoomInfoResp();
            BeanUtils.copyProperties(meetingRoom, meetingRoomInfoResp);
            SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
            meetingRoomInfoResp.setBuildingName(building.getName());
            SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
            meetingRoomInfoResp.setFloorName(floor.getName());
            applyResp.setMeetingRoomInfo(meetingRoomInfoResp);
        }

        SmsUser smsUser = cacheUtil.getUserInfo(applyResp.getApplyUserId());
        SmsSearchUserResp smsUserResp = new SmsSearchUserResp();
        if (smsUser != null) {
            BeanUtils.copyProperties(smsUser, smsUserResp);
        }
        applyResp.setApplyUserInfo(smsUserResp);

        List<MeetingRoomProcessDetailResp> detailRespList = smsMeetingRoomProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsMeetingRoomProcessDetail>()
                        .eq(SmsMeetingRoomProcessDetail::getApplyId, applyId)
                        .orderByDesc(SmsMeetingRoomProcessDetail::getCreateTime))
                .stream().map(detail -> {
                    MeetingRoomProcessDetailResp detailResp = new MeetingRoomProcessDetailResp();
                    BeanUtils.copyProperties(detail, detailResp);
                    //如果有审批人,对审批人进行封装
                    if (!isNullOrEmpty(detailResp.getUserId())) {
                        SmsUser userInfo = cacheUtil.getUserInfo(detailResp.getUserId());
                        SmsSearchUserResp smsSearchUserResp = new SmsSearchUserResp();
                        if (userInfo != null) {
                            BeanUtils.copyProperties(userInfo, smsSearchUserResp);
                        }
                        detailResp.setAllowUserInfo(smsSearchUserResp);
                    }
                    SmsUser allowUser = cacheUtil.getUserInfo(detail.getUserId());
                    if (allowUser != null) {
                        detailResp.setUserName(allowUser.getRealName());
                        detailResp.setUserPic(allowUser.getUserPic());
                    }
                    return detailResp;
                }).collect(Collectors.toList());

        applyResp.setProcessList(detailRespList);

        return CommonResult.success(applyResp);
    }

    @Override
    @Transactional
    public ResponseResult allowPredetermineApply(SmsPredetermineApplyAllowReq allowReq, String userId) {
        //校验前端参数
        if (isNullOrEmpty(allowReq.getApplyId()) || isNullOrEmpty(allowReq.getDetailId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //若传入参数非“通过”且非“驳回”,进行阻断
        if (allowReq.getAllowStatus() != MEETING_DETAIL_ALLOW_STATUS_PASS && allowReq.getAllowStatus() != MEETING_DETAIL_ALLOW_STATUS_DENY) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //校验申请表是否存在
        SmsMeetingRoomPredetermineApply predetermineApply = smsMeetingRoomPredetermineApplyMapper.selectById(allowReq.getApplyId());
        if (isNullOrEmpty(predetermineApply)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_APPLY_NOT_EXIST);
        }

        //校验该节点是否为“待审批”状态
        SmsMeetingRoomProcessDetail processDetail = smsMeetingRoomProcessDetailMapper.selectById(allowReq.getDetailId());
        if (isNullOrEmpty(processDetail) || processDetail.getAllowStatus() != MEETING_DETAIL_ALLOW_STATUS_WAIT) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_ALLOWED_FAIL);
        }

        //判断该节点是否本人审批
        if (!processDetail.getUserId().equals(userId)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_ALLOWED_FAIL);
        }

        //修改节点表
        SmsMeetingRoomProcessDetail allowDetail = new SmsMeetingRoomProcessDetail();
        allowDetail.setId(allowReq.getDetailId());
        allowDetail.setAllowStatus(allowReq.getAllowStatus());
        if (!isNullOrEmpty(allowReq.getRemark())) {
            allowDetail.setRemark(allowReq.getRemark());
        }
        allowDetail.setEndTime(new Date());
        allowDetail.setUserId(userId);
        //设置签名
        if (processDetail.getIsSign() == MEETING_ROOM_BOOLEAN_TRUE) {
            if (isNullOrEmpty(allowReq.getSign())) {
                return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
            }
            allowDetail.setSign(allowReq.getSign());
        }
        //设置印章
        if (processDetail.getIsStamp() == MEETING_ROOM_BOOLEAN_TRUE) {
            if (isNullOrEmpty(allowReq.getStamp())) {
                return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
            }
            allowDetail.setStamp(allowReq.getStamp());
        }
        smsMeetingRoomProcessDetailMapper.updateById(allowDetail);

        //修改申请表
        SmsMeetingRoomPredetermineApply updateApply = new SmsMeetingRoomPredetermineApply();
        updateApply.setId(allowReq.getApplyId());
        updateApply.setEndTime(new Date());
        updateApply.setAllowStatus(allowReq.getAllowStatus());
        smsMeetingRoomPredetermineApplyMapper.updateById(updateApply);

        //消息通知
        boolean result_status = false;//流程状态
        if (allowReq.getAllowStatus() == MEETING_DETAIL_ALLOW_STATUS_PASS) {
            result_status = true;
        }
        newTipsUtil.allowFinishTips(allowReq.getApplyId(), userId, result_status);

        return CommonResult.success();
    }

    @Override
    public ResponseResult listMeetingRoomByTime(String dateStr, String buildingId, Integer capacity, String searchStr) {
        Date date = TimeUtil.StringtoDate(dateStr);
        if (isNullOrEmpty(date)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        LambdaQueryWrapper<SmsMeetingRoomInfo> meetingRoomQueryWrapper = new LambdaQueryWrapper<>();
        meetingRoomQueryWrapper.eq(SmsMeetingRoomInfo::getIsUse, true);
        if (!isNullOrEmpty(buildingId)) {
            meetingRoomQueryWrapper.eq(SmsMeetingRoomInfo::getBuildingId, buildingId);
        }

        if (!isNullOrEmpty(capacity)) {
            meetingRoomQueryWrapper.ge(SmsMeetingRoomInfo::getCapacity, capacity);
        }

        if (!isNullOrEmpty(searchStr)) {
            meetingRoomQueryWrapper.like(SmsMeetingRoomInfo::getName, searchStr)
                    .or().like(SmsMeetingRoomInfo::getRoomNum, searchStr)
                    .or().like(SmsMeetingRoomInfo::getRemark, searchStr);
        }

        List<SmsMeetingRoomInfo> smsMeetingRoomList = smsMeetingRoomInfoMapper.selectList(meetingRoomQueryWrapper);
        List<MeetingRoomAndApplyResp> smsMeetingRoomRespList = smsMeetingRoomList.stream().map(meetingRoom -> {
            MeetingRoomAndApplyResp meetingRoomAndApplyResp = new MeetingRoomAndApplyResp();
            BeanUtils.copyProperties(meetingRoom, meetingRoomAndApplyResp);
            meetingRoomAndApplyResp.setDeviceList(JSON.parseArray(meetingRoom.getDeviceList(), String.class));
            meetingRoomAndApplyResp.setAllowUserIdList(JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class));
            meetingRoomAndApplyResp.setStartTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getStartTimeLimit()));
            meetingRoomAndApplyResp.setEndTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getEndTimeLimit()));
            SmsOrgStructure org = smsOrgStructureMapper.selectById(meetingRoom.getOrgId());
            meetingRoomAndApplyResp.setOrgName(org.getOrgName());
            SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
            meetingRoomAndApplyResp.setBuildingName(building.getName());
            SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
            meetingRoomAndApplyResp.setFloorName(floor.getName());

            LambdaQueryWrapper<SmsMeetingRoomPredetermineApply> meetingRoomWrapper = new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                    .eq(SmsMeetingRoomPredetermineApply::getMeetingRoomId, meetingRoomAndApplyResp.getId())
                    .ge(SmsMeetingRoomPredetermineApply::getStartTime, TimeUtil.GetStartDate(date))
                    .le(SmsMeetingRoomPredetermineApply::getStartTime, TimeUtil.GetEndDate(date))
                    .eq(SmsMeetingRoomPredetermineApply::getAllowStatus, MEETING_ALLOW_STATUS_PASS);

            List<SmsMeetingRoomPredetermineApply> applyList = smsMeetingRoomPredetermineApplyMapper.selectList(meetingRoomWrapper);

            DateAndTimeRangeResp dateAndTimeRangeResp = new DateAndTimeRangeResp();
            dateAndTimeRangeResp.setDate(TimeUtil.DateSimpleformat(date));
            dateAndTimeRangeResp.setDayOfWeek(TimeUtil.getWeek(date));

            List<TimeRangeResp> timeRangeRespList = applyList.stream().map(apply -> {
                TimeRangeResp timeRangeResp = new TimeRangeResp();
                timeRangeResp.setStartTime(TimeUtil.TimeFormatSting(apply.getStartTime()));
                timeRangeResp.setEndTime(TimeUtil.TimeFormatSting(apply.getEndTime()));
                return timeRangeResp;
            }).collect(Collectors.toList());

            dateAndTimeRangeResp.setTimeRangeList(timeRangeRespList);
            List<DateAndTimeRangeResp> dateAndTimeRangeRespList = new ArrayList<>();
            dateAndTimeRangeRespList.add(dateAndTimeRangeResp);

            meetingRoomAndApplyResp.setDateAndTimeRangeList(dateAndTimeRangeRespList);

            return meetingRoomAndApplyResp;
        }).collect(Collectors.toList());

        return CommonResult.success(smsMeetingRoomRespList, smsMeetingRoomRespList.size());
    }

    @Override
    public ResponseResult listMeetingRoomByTimeDetail(String dateStr, String id) {
        Date date = TimeUtil.StringtoDate(dateStr);
        if (isNullOrEmpty(date) || isNullOrEmpty(id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsMeetingRoomInfo meetingRoom = smsMeetingRoomInfoMapper.selectById(id);
        if (isNullOrEmpty(meetingRoom)) {
            return CommonResult.failed(CommonCodeEnum.MEETING_ROOM_NOT_EXIST);
        }

        MeetingRoomAndApplyResp meetingRoomAndApplyResp = new MeetingRoomAndApplyResp();
        BeanUtils.copyProperties(meetingRoom, meetingRoomAndApplyResp);
        meetingRoomAndApplyResp.setDeviceList(JSON.parseArray(meetingRoom.getDeviceList(), String.class));
        meetingRoomAndApplyResp.setAllowUserIdList(JSON.parseArray(meetingRoom.getAllowUserIdList(), String.class));
        meetingRoomAndApplyResp.setStartTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getStartTimeLimit()));
        meetingRoomAndApplyResp.setEndTimeLimit(TimeUtil.TimeFormatSting(meetingRoom.getEndTimeLimit()));
        SmsOrgStructure org = smsOrgStructureMapper.selectById(meetingRoom.getOrgId());
        meetingRoomAndApplyResp.setOrgName(org.getOrgName());
        SmsMeetingBuilding building = smsMeetingBuildingMapper.selectById(meetingRoom.getBuildingId());
        meetingRoomAndApplyResp.setBuildingName(building.getName());
        SmsMeetingBuildingFloor floor = smsMeetingBuildingFloorMapper.selectById(meetingRoom.getFloorId());
        meetingRoomAndApplyResp.setFloorName(floor.getName());

        List<DateAndTimeRangeResp> dateAndTimeRangeRespList = new ArrayList<>();
        int offset = 0;
        for (int i = 0; i < 7; i++) {

            LambdaQueryWrapper<SmsMeetingRoomPredetermineApply> meetingRoomWrapper = new LambdaQueryWrapper<SmsMeetingRoomPredetermineApply>()
                    .eq(SmsMeetingRoomPredetermineApply::getMeetingRoomId, meetingRoomAndApplyResp.getId())
                    .ge(SmsMeetingRoomPredetermineApply::getStartTime, TimeUtil.GetStartDate(TimeUtil.AddDays(date, offset)))
                    .le(SmsMeetingRoomPredetermineApply::getStartTime, TimeUtil.GetEndDate(TimeUtil.AddDays(date, offset)))
                    .eq(SmsMeetingRoomPredetermineApply::getAllowStatus, MEETING_ALLOW_STATUS_PASS);

            List<SmsMeetingRoomPredetermineApply> applyList = smsMeetingRoomPredetermineApplyMapper.selectList(meetingRoomWrapper);
            DateAndTimeRangeResp dateAndTimeRangeResp = new DateAndTimeRangeResp();
            dateAndTimeRangeResp.setDate(TimeUtil.DateSimpleformat(TimeUtil.AddDays(date, offset)));
            dateAndTimeRangeResp.setDayOfWeek(TimeUtil.getWeek(TimeUtil.AddDays(date, offset)));

            List<TimeRangeResp> timeRangeRespList = applyList.stream().map(apply -> {
                TimeRangeResp timeRangeResp = new TimeRangeResp();
                BeanUtils.copyProperties(apply, timeRangeResp);
                timeRangeResp.setStartTime(TimeUtil.TimeFormatSting(apply.getStartTime()));
                timeRangeResp.setEndTime(TimeUtil.TimeFormatSting(apply.getEndTime()));
                SmsUser userInfo = cacheUtil.getUserInfo(timeRangeResp.getUserId());
                SmsSearchUserResp smsSearchUserResp = new SmsSearchUserResp();
                if (userInfo != null) {
                    BeanUtils.copyProperties(userInfo, smsSearchUserResp);
                }
                timeRangeResp.setUserInfo(smsSearchUserResp);
                return timeRangeResp;
            }).collect(Collectors.toList());

            dateAndTimeRangeResp.setTimeRangeList(timeRangeRespList);
            dateAndTimeRangeRespList.add(dateAndTimeRangeResp);
            offset++;
        }

        meetingRoomAndApplyResp.setDateAndTimeRangeList(dateAndTimeRangeRespList);

        return CommonResult.success(meetingRoomAndApplyResp);
    }
}
